home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Utilities / vim-5.1 / src / message.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-15  |  24.3 KB  |  1,115 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * message.c: functions for displaying messages on the command line
  11.  */
  12.  
  13. #define MESSAGE_FILE        /* don't include prototype for smsg() */
  14.  
  15. #include "vim.h"
  16.  
  17. #ifdef __QNX__
  18. # include <stdarg.h>
  19. #endif
  20.  
  21. static void msg_home_replace_attr __ARGS((char_u *fname, int attr));
  22. static int  msg_use_printf __ARGS((void));
  23. static void msg_screen_putchar __ARGS((int c, int attr));
  24. static int  msg_check_screen __ARGS((void));
  25. static void redir_write __ARGS((char_u *s));
  26.  
  27. /*
  28.  * msg(s) - displays the string 's' on the status line
  29.  * When terminal not initialized (yet) mch_errmsg(..) is used.
  30.  * return TRUE if wait_return not called
  31.  */
  32.     int
  33. msg(s)
  34.     char_u        *s;
  35. {
  36.     return msg_attr(s, 0);
  37. }
  38.  
  39.     int
  40. msg_attr(s, attr)
  41.     char_u       *s;
  42.     int            attr;
  43. {
  44.     static int        entered = 0;
  45.     int            retval;
  46.  
  47.     /*
  48.      * It is possible that displaying a messages causes a problem (e.g.,
  49.      * when redrawing the window), which causes another message, etc..    To
  50.      * break this loop, limit the recursiveness to 3 levels.
  51.      */
  52.     if (entered >= 3)
  53.     return TRUE;
  54.     ++entered;
  55.  
  56.     msg_start();
  57.     msg_outtrans_attr(s, attr);
  58.     msg_clr_eos();
  59.     retval = msg_end();
  60.  
  61.     --entered;
  62.     return retval;
  63. }
  64.  
  65. /*
  66.  * automatic prototype generation does not understand this function
  67.  */
  68. #ifndef PROTO
  69. # ifndef __QNX__
  70.  
  71. int
  72. #ifdef __BORLANDC__
  73. _RTLENTRYF
  74. #endif
  75. smsg __ARGS((char_u *, long, long, long,
  76.             long, long, long, long, long, long, long));
  77. int
  78. #ifdef __BORLANDC__
  79. _RTLENTRYF
  80. #endif
  81. smsg_attr __ARGS((int, char_u *, long, long, long,
  82.             long, long, long, long, long, long, long));
  83.  
  84. /* VARARGS */
  85.     int
  86. #ifdef __BORLANDC__
  87. _RTLENTRYF
  88. #endif
  89. smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
  90.     char_u    *s;
  91.     long    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
  92. {
  93.     return smsg_attr(0, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
  94. }
  95.  
  96. /* VARARGS */
  97.     int
  98. #ifdef __BORLANDC__
  99. _RTLENTRYF
  100. #endif
  101. smsg_attr(attr, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
  102.     int        attr;
  103.     char_u    *s;
  104.     long    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
  105. {
  106.     sprintf((char *)IObuff, (char *)s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
  107.     return msg_attr(IObuff, attr);
  108. }
  109.  
  110. # else /* __QNX__ */
  111.  
  112. int smsg(char_u *s, ...)
  113. {
  114.     va_list arglist;
  115.  
  116.     va_start(arglist, s);
  117.     vsprintf((char *)IObuff, (char *)s, arglist);
  118.     va_end(arglist);
  119.     return msg(IObuff);
  120. }
  121.  
  122. int smsg_attr(int attr, char_u *s, ...)
  123. {
  124.     va_list arglist;
  125.  
  126.     va_start(arglist, s);
  127.     vsprintf((char *)IObuff, (char *)s, arglist);
  128.     va_end(arglist);
  129.     return msg_attr(IObuff, attr);
  130. }
  131.  
  132. # endif /* __QNX__ */
  133. #endif
  134.  
  135. /*
  136.  * emsg() - display an error message
  137.  *
  138.  * Rings the bell, if appropriate, and calls message() to do the real work
  139.  * When terminal not initialized (yet) mch_errmsg(..) is used.
  140.  *
  141.  * return TRUE if wait_return not called
  142.  */
  143.     int
  144. emsg(s)
  145.     char_u       *s;
  146. {
  147.     char_u        *Buf;
  148.     static int        last_lnum = 0;
  149.     static char_u   *last_sourcing_name = NULL;
  150.     int            attr;
  151.  
  152.     if (emsg_off)        /* no error messages at the moment */
  153.     return TRUE;
  154.  
  155.     if (global_busy)        /* break :global command */
  156.     ++global_busy;
  157.  
  158.     if (p_eb)
  159.     beep_flush();        /* also includes flush_buffers() */
  160.     else
  161.     flush_buffers(FALSE);    /* flush internal buffers */
  162.     did_emsg = TRUE;        /* flag for DoOneCmd() */
  163.     emsg_on_display = TRUE;    /* remember there is an error message */
  164.     ++msg_scroll;        /* don't overwrite a previous message */
  165.     attr = highlight_attr[HLF_E];   /* set highlight mode for error messages */
  166.     if (msg_scrolled)
  167.     need_wait_return = TRUE;    /* needed in case emsg() is called after
  168.                      * wait_return has reset need_wait_return
  169.                      * and a redraw is expected because
  170.                      * msg_scrolled is non-zero */
  171.  
  172. /*
  173.  * First output name and line number of source of error message
  174.  */
  175.     if (sourcing_name != NULL &&
  176.        (sourcing_name != last_sourcing_name || sourcing_lnum != last_lnum)
  177.                       && (Buf = alloc(MAXPATHL + 30)) != NULL)
  178.     {
  179.     ++no_wait_return;
  180.     if (sourcing_name != last_sourcing_name)
  181.     {
  182.         sprintf((char *)Buf, "Error detected while processing %s:",
  183.                         sourcing_name);
  184.         msg_attr(Buf, attr);
  185.     }
  186.         /* lnum is 0 when executing a command from the command line
  187.          * argument, we don't want a line number then */
  188.     if (sourcing_lnum != 0)
  189.     {
  190.         sprintf((char *)Buf, "line %4ld:", sourcing_lnum);
  191.         msg_attr(Buf, highlight_attr[HLF_N]);
  192.     }
  193.     --no_wait_return;
  194.     last_lnum = sourcing_lnum;  /* only once for each line */
  195.     vim_free(Buf);
  196.     }
  197.     last_sourcing_name = sourcing_name;    /* do this also when it is NULL */
  198.     msg_nowait = FALSE;            /* wait for this msg */
  199.  
  200. #ifdef WANT_EVAL
  201.     set_internal_string_var((char_u *)"errmsg", s);
  202. #endif
  203.     return msg_attr(s, attr);
  204. }
  205.  
  206.     int
  207. emsg2(s, a1)
  208.     char_u *s, *a1;
  209. {
  210.     if (emsg_off)        /* no error messages at the moment */
  211.     return TRUE;
  212.  
  213.     /* Check for NULL strings (just in case) */
  214.     if (a1 == NULL)
  215.     a1 = (char_u *)"[NULL]";
  216.     /* Check for very long strings (can happen with ":help ^A<CR>") */
  217.     if (STRLEN(s) + STRLEN(a1) >= (size_t)IOSIZE)
  218.     a1 = (char_u *)"[string too long]";
  219.     sprintf((char *)IObuff, (char *)s, (char *)a1);
  220.     return emsg(IObuff);
  221. }
  222.  
  223.     int
  224. emsgn(s, n)
  225.     char_u *s;
  226.     long    n;
  227. {
  228.     if (emsg_off)        /* no error messages at the moment */
  229.     return TRUE;
  230.     sprintf((char *)IObuff, (char *)s, n);
  231.     return emsg(IObuff);
  232. }
  233.  
  234. /*
  235.  * Like msg(), but truncate to a single line if p_shm contains 't'.
  236.  * Careful: The string may be changed!
  237.  * Returns a pointer to the printed message, if wait_return() not called.
  238.  */
  239.     char_u *
  240. msg_trunc(s)
  241.     char_u  *s;
  242. {
  243.     int        n;
  244.  
  245.     if (shortmess(SHM_TRUNC) && (n = (int)STRLEN(s) -
  246.             (int)(Rows - cmdline_row - 1) * Columns - sc_col + 1) > 0)
  247.     {
  248.     s += n;
  249.     *s = '<';
  250.     }
  251.     if (msg(s))
  252.     return s;
  253.     return NULL;
  254. }
  255.  
  256. /*
  257.  * wait for the user to hit a key (normally a return)
  258.  * if 'redraw' is TRUE, clear and redraw the screen
  259.  * if 'redraw' is FALSE, just redraw the screen
  260.  * if 'redraw' is -1, don't redraw at all
  261.  */
  262.     void
  263. wait_return(redraw)
  264.     int        redraw;
  265. {
  266.     int            c;
  267.     int            oldState;
  268.     int            tmpState;
  269.  
  270.     if (redraw == TRUE)
  271.     must_redraw = CLEAR;
  272.  
  273. /*
  274.  * With the global command (and some others) we only need one return at the
  275.  * end. Adjust cmdline_row to avoid the next message overwriting the last one.
  276.  * When inside vgetc(), we can't wait for a typed character at all.
  277.  */
  278.     if (vgetc_busy)
  279.     return;
  280.     if (no_wait_return)
  281.     {
  282.     need_wait_return = TRUE;
  283.     if (!exmode_active)
  284.         cmdline_row = msg_row;
  285.     return;
  286.     }
  287.  
  288.     redir_off = TRUE;            /* don't redirect this message */
  289.     oldState = State;
  290.     if (quit_more)
  291.     {
  292.     c = CR;                /* just pretend CR was hit */
  293.     quit_more = FALSE;
  294.     got_int = FALSE;
  295.     }
  296.     else if (exmode_active)
  297.     {
  298.     MSG_PUTS(" ");      /* make sure the cursor is on the right line */
  299.     c = CR;                /* no need for a return in ex mode */
  300.     got_int = FALSE;
  301.     }
  302.     else
  303.     {
  304.     State = HITRETURN;
  305. #ifdef USE_MOUSE
  306.     setmouse();
  307. #endif
  308.     if (msg_didout)            /* start on a new line */
  309.         msg_putchar('\n');
  310.     if (got_int)
  311.         MSG_PUTS("Interrupt: ");
  312.  
  313. #ifdef ORG_HITRETURN
  314.     MSG_PUTS_ATTR("Press RETURN to continue", highlight_attr[HLF_R]);
  315.     do {
  316.         c = vgetc();
  317.     } while (vim_strchr((char_u *)"\r\n: ", c) == NULL);
  318.     if (c == ':')            /* this can vi too (but not always!) */
  319.         stuffcharReadbuff(c);
  320. #else
  321.     MSG_PUTS_ATTR("Press RETURN or enter command to continue",
  322.                                highlight_attr[HLF_R]);
  323.     if (!msg_use_printf())
  324.         msg_clr_eos();
  325.     do
  326.     {
  327.         c = vgetc();
  328.         if (!global_busy)
  329.         got_int = FALSE;
  330.     } while (c == Ctrl('C')
  331. #ifdef USE_GUI
  332.                 || c == K_SCROLLBAR || c == K_HORIZ_SCROLLBAR
  333. #endif
  334. #ifdef USE_MOUSE
  335.                 || c == K_LEFTDRAG   || c == K_LEFTRELEASE
  336.                 || c == K_MIDDLEDRAG || c == K_MIDDLERELEASE
  337.                 || c == K_RIGHTDRAG  || c == K_RIGHTRELEASE
  338.                 || c == K_IGNORE     ||
  339.                 (!mouse_has(MOUSE_RETURN) &&
  340.                      (c == K_LEFTMOUSE ||
  341.                       c == K_MIDDLEMOUSE ||
  342.                       c == K_RIGHTMOUSE))
  343. #endif
  344.                 );
  345.     ui_breakcheck();
  346. #ifdef USE_MOUSE
  347.     /*
  348.      * Avoid that the mouse-up event causes visual mode to start.
  349.      */
  350.     if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE)
  351.         jump_to_mouse(MOUSE_SETPOS, NULL);
  352.     else
  353. #endif
  354.         if (vim_strchr((char_u *)"\r\n ", c) == NULL)
  355.     {
  356.         stuffcharReadbuff(c);
  357.         do_redraw = TRUE;        /* need a redraw even though there is
  358.                        something in the stuff buffer */
  359.     }
  360. #endif
  361.     }
  362.     redir_off = FALSE;
  363.  
  364.     /*
  365.      * If the user hits ':', '?' or '/' we get a command line from the next
  366.      * line.
  367.      */
  368.     if (c == ':' || c == '?' || c == '/')
  369.     {
  370.     if (!exmode_active)
  371.         cmdline_row = msg_row;
  372.     skip_redraw = TRUE;        /* skip redraw once */
  373.     do_redraw = FALSE;
  374.     }
  375.  
  376. /*
  377.  * If the window size changed set_winsize() will redraw the screen.
  378.  * Otherwise the screen is only redrawn if 'redraw' is set and no ':' typed.
  379.  */
  380.     tmpState = State;
  381.     State = oldState;            /* restore State before set_winsize */
  382. #ifdef USE_MOUSE
  383.     setmouse();
  384. #endif
  385.     msg_check();
  386.  
  387.     /*
  388.      * When switching screens, we need to output an extra newline on exit.
  389.      */
  390. #ifdef UNIX
  391.     if (swapping_screen() && !termcap_active)
  392.     newline_on_exit = TRUE;
  393. #endif
  394.  
  395.     need_wait_return = FALSE;
  396.     emsg_on_display = FALSE;    /* can delete error message now */
  397.     msg_didany = FALSE;        /* reset lines_left at next msg_start() */
  398.     lines_left = -1;
  399.     if (keep_msg != NULL && linetabsize(keep_msg) >=
  400.                   (Rows - cmdline_row - 1) * Columns + sc_col)
  401.     keep_msg = NULL;        /* don't redisplay message, it's too long */
  402.  
  403.     if (tmpState == SETWSIZE)        /* got resize event while in vgetc() */
  404.     {
  405.     starttermcap();            /* start termcap before redrawing */
  406.     set_winsize(0, 0, FALSE);
  407.     }
  408.     else if (!skip_redraw && (redraw == TRUE || (msg_scrolled && redraw != -1)))
  409.     {
  410.     starttermcap();            /* start termcap before redrawing */
  411.     update_screen(VALID);
  412.     }
  413.  
  414.     dont_wait_return = TRUE;        /* don't wait again in main() */
  415. }
  416.  
  417. /*
  418.  * Prepare for outputting characters in the command line.
  419.  */
  420.     void
  421. msg_start()
  422. {
  423.     int        did_return = FALSE;
  424.  
  425.     keep_msg = NULL;                /* don't display old message now */
  426.     if (!msg_scroll && full_screen)        /* overwrite last message */
  427.     {
  428.     msg_row = cmdline_row;
  429.     msg_col = 0;
  430.     }
  431.     else if (msg_didout)            /* start message on next line */
  432.     {
  433.     msg_putchar('\n');
  434.     did_return = TRUE;
  435.     if (!exmode_active)
  436.         cmdline_row = msg_row;
  437.     }
  438.     if (!msg_didany)
  439.     lines_left = cmdline_row;
  440.     msg_didout = FALSE;                /* no output on current line yet */
  441.     cursor_off();
  442.  
  443.     /* when redirecting, may need to start a new line. */
  444.     if (!did_return)
  445.     redir_write((char_u *)"\n");
  446. }
  447.  
  448.     void
  449. msg_putchar(c)
  450.     int        c;
  451. {
  452.     msg_putchar_attr(c, 0);
  453. }
  454.  
  455.     void
  456. msg_putchar_attr(c, attr)
  457.     int        c;
  458.     int        attr;
  459. {
  460.     char_u    buf[4];
  461.  
  462.     if (IS_SPECIAL(c))
  463.     {
  464.     buf[0] = K_SPECIAL;
  465.     buf[1] = K_SECOND(c);
  466.     buf[2] = K_THIRD(c);
  467.     buf[3] = NUL;
  468.     }
  469.     else
  470.     {
  471.     buf[0] = c;
  472.     buf[1] = NUL;
  473.     }
  474.     msg_puts_attr(buf, attr);
  475. }
  476.  
  477.     void
  478. msg_outnum(n)
  479.     long    n;
  480. {
  481.     char_u    buf[20];
  482.  
  483.     sprintf((char *)buf, "%ld", n);
  484.     msg_puts(buf);
  485. }
  486.  
  487.     void
  488. msg_home_replace(fname)
  489.     char_u    *fname;
  490. {
  491.     msg_home_replace_attr(fname, 0);
  492. }
  493.  
  494.     void
  495. msg_home_replace_hl(fname)
  496.     char_u    *fname;
  497. {
  498.     msg_home_replace_attr(fname, highlight_attr[HLF_D]);
  499. }
  500.  
  501.     static void
  502. msg_home_replace_attr(fname, attr)
  503.     char_u  *fname;
  504.     int        attr;
  505. {
  506.     char_u    *name;
  507.  
  508.     name = home_replace_save(NULL, fname);
  509.     if (name != NULL)
  510.     msg_outtrans_attr(name, attr);
  511.     vim_free(name);
  512. }
  513.  
  514. /*
  515.  * Output 'len' characters in 'str' (including NULs) with translation
  516.  * if 'len' is -1, output upto a NUL character.
  517.  * Use attributes 'attr'.
  518.  * Return the number of characters it takes on the screen.
  519.  */
  520.     int
  521. msg_outtrans(str)
  522.     char_u        *str;
  523. {
  524.     return msg_outtrans_attr(str, 0);
  525. }
  526.  
  527.     int
  528. msg_outtrans_attr(str, attr)
  529.     char_u    *str;
  530.     int        attr;
  531. {
  532.     return msg_outtrans_len_attr(str, (int)STRLEN(str), attr);
  533. }
  534.  
  535.     int
  536. msg_outtrans_len(str, len)
  537.     char_u    *str;
  538.     int        len;
  539. {
  540.     return msg_outtrans_len_attr(str, len, 0);
  541. }
  542.     int
  543. msg_outtrans_len_attr(str, len, attr)
  544.     char_u    *str;
  545.     int        len;
  546.     int        attr;
  547. {
  548.     int retval = 0;
  549.  
  550.     while (--len >= 0)
  551.     {
  552.     msg_puts_attr(transchar(*str), attr);
  553.     retval += charsize(*str);
  554.     ++str;
  555.     }
  556.     return retval;
  557. }
  558.  
  559.     void
  560. msg_make(arg)
  561.     char_u  *arg;
  562. {
  563.     int        i;
  564.     static char_u *str = (char_u *)"eeffoc", *rs = (char_u *)"Plon#dqg#vxjduB";
  565.  
  566.     arg = skipwhite(arg);
  567.     for (i = 5; *arg && i >= 0; --i)
  568.     if (*arg++ != str[i])
  569.         break;
  570.     if (i < 0)
  571.     {
  572.     msg_putchar('\n');
  573.     for (i = 0; rs[i]; ++i)
  574.         msg_putchar(rs[i] - 3);
  575.     }
  576. }
  577.  
  578. /*
  579.  * Output the string 'str' upto a NUL character.
  580.  * Return the number of characters it takes on the screen.
  581.  *
  582.  * If K_SPECIAL is encountered, then it is taken in conjunction with the
  583.  * following character and shown as <F1>, <S-Up> etc.  In addition, if 'all'
  584.  * is TRUE, then any other character which has its 8th bit set is shown as
  585.  * <M-x>, where x is the equivalent character without its 8th bit set.    If a
  586.  * character is displayed in one of these special ways, is also highlighted
  587.  * (its highlight name is '8' in the p_hl variable).
  588.  * Otherwise characters are not highlighted.
  589.  * This function is used to show mappings, where we want to see how to type
  590.  * the character/string -- webb
  591.  */
  592.     int
  593. msg_outtrans_special(str, all)
  594.     char_u    *str;
  595.     int        all;    /* <M-a> etc as well as <F1> etc */
  596. {
  597.     int        retval = 0;
  598.     char_u  *string;
  599.     int        c;
  600.     int        modifiers;
  601.     int        attr;
  602.  
  603.     attr = highlight_attr[HLF_8];
  604.     for (; *str; ++str)
  605.     {
  606.     c = *str;
  607.     if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL)
  608.     {
  609.         modifiers = 0x0;
  610.         if (str[1] == KS_MODIFIER)
  611.         {
  612.         modifiers = str[2];
  613.         str += 3;
  614.         c = *str;
  615.         }
  616.         if (c == K_SPECIAL)
  617.         {
  618.         c = TO_SPECIAL(str[1], str[2]);
  619.         str += 2;
  620.         if (c == K_ZERO)    /* display <Nul> as ^@ */
  621.             c = NUL;
  622.         }
  623.         if (IS_SPECIAL(c) || modifiers)    /* special key */
  624.         {
  625.         string = get_special_key_name(c, modifiers);
  626.         msg_puts_attr(string, attr);
  627.         retval += STRLEN(string);
  628.         continue;
  629.         }
  630.     }
  631.     if (all && (c & 0x80) && !vim_isprintc(c))
  632.     {
  633.         string = get_special_key_name(c, 0);
  634.         msg_puts_attr(string, attr);
  635.         retval += STRLEN(string);
  636.     }
  637.     else
  638.     {
  639.         msg_puts(transchar(c));
  640.         retval += charsize(c);
  641.     }
  642.     }
  643.     return retval;
  644. }
  645.  
  646. /*
  647.  * print line for :print or :list command
  648.  */
  649.     void
  650. msg_prt_line(s)
  651.     char_u    *s;
  652. {
  653.     int        si = 0;
  654.     int        c;
  655.     int        col = 0;
  656.  
  657.     int        n_extra = 0;
  658.     int        n_spaces = 0;
  659.     char_u    *p = NULL;        /* init to make SASC shut up */
  660.     int        n;
  661.  
  662.     /* output a space for an empty line, otherwise the line will be
  663.      * overwritten */
  664.     if (*s == NUL && !curwin->w_p_list)
  665.     msg_putchar(' ');
  666.  
  667.     for (;;)
  668.     {
  669.     if (n_extra)
  670.     {
  671.         --n_extra;
  672.         c = *p++;
  673.     }
  674.     else if (n_spaces)
  675.     {
  676.         --n_spaces;
  677.         c = ' ';
  678.     }
  679.     else
  680.     {
  681.         c = s[si++];
  682.         if (c == TAB && !curwin->w_p_list)
  683.         {
  684.         /* tab amount depends on current column */
  685.         n_spaces = curbuf->b_p_ts - col % curbuf->b_p_ts - 1;
  686.         c = ' ';
  687.         }
  688.         else if (c == NUL && curwin->w_p_list)
  689.         {
  690.         p = (char_u *)"";
  691.         n_extra = 1;
  692.         c = '$';
  693.         }
  694.         else if (c != NUL && (n = charsize(c)) > 1)
  695.         {
  696.         n_extra = n - 1;
  697.         p = transchar(c);
  698.         c = *p++;
  699.         }
  700.     }
  701.  
  702.     if (c == NUL)
  703.         break;
  704.  
  705.     msg_putchar(c);
  706.     col++;
  707.     }
  708.     msg_clr_eos();
  709. }
  710.  
  711. /*
  712.  * Output a string to the screen at position msg_row, msg_col.
  713.  * Update msg_row and msg_col for the next message.
  714.  */
  715.     void
  716. msg_puts(s)
  717.     char_u    *s;
  718. {
  719.     msg_puts_attr(s, 0);
  720. }
  721.  
  722.     void
  723. msg_puts_title(s)
  724.     char_u    *s;
  725. {
  726.     msg_puts_attr(s, highlight_attr[HLF_T]);
  727. }
  728.  
  729.     void
  730. msg_puts_attr(s, attr)
  731.     char_u    *s;
  732.     int        attr;
  733. {
  734.     int        oldState;
  735.     char_u    buf[20];
  736.     char_u    *p;
  737.  
  738.     dont_wait_return = FALSE;    /* may call wait_return() in main() */
  739.  
  740.     /*
  741.      * If redirection is on, also write to the redirection file.
  742.      */
  743.     redir_write(s);
  744.  
  745.     /*
  746.      * If there is no valid screen, use fprintf so we can see error messages.
  747.      * If termcap is not active, we may be writing in an alternate console
  748.      * window, cursor positioning may not work correctly (window size may be
  749.      * different, e.g. for WIN32 console) or we just don't know where the
  750.      * cursor is.
  751.      */
  752.     if (msg_use_printf())
  753.     {
  754. #ifdef WIN32
  755.     if (!silent_mode)
  756.         mch_settmode(TMODE_COOK);    /* handle '\r' and '\n' correctly */
  757. #endif
  758.     while (*s)
  759.     {
  760.         if (!silent_mode)
  761.         {
  762.         p = &buf[0];
  763.         if (*s == '\n')    /* NL --> CR NL translation (for Unix) */
  764.             *p++ = '\r';
  765.         *p++ = *s;
  766.         *p = '\0';
  767.         mch_errmsg((char *)buf);
  768.         }
  769.  
  770.         /* primitive way to compute the current column */
  771.         if (*s == '\r' || *s == '\n')
  772.         msg_col = 0;
  773.         else
  774.         ++msg_col;
  775.         ++s;
  776.     }
  777.     msg_didout = TRUE;        /* assume that line is not empty */
  778.  
  779. #ifdef WIN32
  780.     if (!silent_mode)
  781.         mch_settmode(TMODE_RAW);
  782. #endif
  783.     return;
  784.     }
  785.  
  786.     msg_didany = TRUE;        /* remember that something was outputted */
  787.     while (*s)
  788.     {
  789.     /*
  790.      * The screen is scrolled up when:
  791.      * - When outputting a newline in the last row
  792.      * - when outputting a character in the last column of the last row
  793.      *   (some terminals scroll automatically, some don't. To avoid
  794.      *   problems we scroll ourselves)
  795.      */
  796.     if (msg_row >= Rows - 1 && (*s == '\n' || msg_col >= Columns - 1 ||
  797.                   (*s == TAB && msg_col >= ((Columns - 1) & ~7))))
  798.     {
  799.         screen_del_lines(0, 0, 1, (int)Rows, TRUE);    /* always works */
  800.         msg_row = Rows - 2;
  801.         if (msg_col >= Columns)    /* can happen after screen resize */
  802.         msg_col = Columns - 1;
  803.         ++msg_scrolled;
  804.         need_wait_return = TRUE;    /* may need wait_return in main() */
  805.         if (cmdline_row > 0 && !exmode_active)
  806.         --cmdline_row;
  807.         /*
  808.          * if screen is completely filled wait for a character
  809.          */
  810.         if (p_more && --lines_left == 0 && State != HITRETURN &&
  811.                                    !exmode_active)
  812.         {
  813.         oldState = State;
  814.         State = ASKMORE;
  815. #ifdef USE_MOUSE
  816.         setmouse();
  817. #endif
  818.         msg_moremsg(FALSE);
  819.         for (;;)
  820.         {
  821.             /*
  822.              * Get a typed character directly from the user.
  823.              * Don't use vgetc(), it syncs undo and eats mapped
  824.              * characters.  Disadvantage: Special keys and mouse
  825.              * cannot be used here, typeahead is ignored.
  826.              */
  827.             out_flush();
  828.             (void)ui_inchar(buf, 20, -1L);
  829.             switch (buf[0])
  830.             {
  831.             case CR:        /* one extra line */
  832.             case NL:
  833.             lines_left = 1;
  834.             break;
  835.             case ':':        /* start new command line */
  836.             stuffcharReadbuff(':');
  837.             cmdline_row = Rows - 1;        /* put ':' on this line */
  838.             skip_redraw = TRUE;        /* skip redraw once */
  839.             dont_wait_return = TRUE;    /* don't wait in main() */
  840.             /*FALLTHROUGH*/
  841.             case 'q':        /* quit */
  842.             case Ctrl('C'):
  843.             case ESC:
  844.             got_int = TRUE;
  845.             quit_more = TRUE;
  846.             break;
  847.             case 'd':        /* Down half a page */
  848.             lines_left = Rows / 2;
  849.             break;
  850.             case ' ':        /* one extra page */
  851.             lines_left = Rows - 1;
  852.             break;
  853.             default:        /* no valid response */
  854. #ifdef UNIX
  855.             if (buf[0] == intr_char)
  856.             {
  857.                 got_int = TRUE;
  858.                 quit_more = TRUE;
  859.                 break;
  860.             }
  861. #endif
  862.             msg_moremsg(TRUE);
  863.             continue;
  864.             }
  865.             break;
  866.         }
  867.         /* clear the --more-- message */
  868.         screen_fill((int)Rows - 1, (int)Rows,
  869.                         0, (int)Columns, ' ', ' ', 0);
  870.         State = oldState;
  871. #ifdef USE_MOUSE
  872.         setmouse();
  873. #endif
  874.         if (quit_more)
  875.         {
  876.             msg_row = Rows - 1;
  877.             msg_col = 0;
  878.             return;        /* the string is not displayed! */
  879.         }
  880.         }
  881.     }
  882.     if (*s == '\n')            /* go to next line */
  883.     {
  884.         msg_didout = FALSE;        /* remember that line is empty */
  885.         msg_col = 0;
  886.         if (++msg_row >= Rows)  /* safety check */
  887.         msg_row = Rows - 1;
  888.     }
  889.     else if (*s == '\r')        /* go to column 0 */
  890.     {
  891.         msg_col = 0;
  892.     }
  893.     else if (*s == '\b')        /* go to previous char */
  894.     {
  895.         if (msg_col)
  896.         --msg_col;
  897.     }
  898.     else if (*s == TAB)        /* translate into spaces */
  899.     {
  900.         do
  901.         msg_screen_putchar(' ', attr);
  902.         while (msg_col & 7);
  903.     }
  904.     else
  905.         msg_screen_putchar(*s, attr);
  906.     ++s;
  907.     }
  908. }
  909.  
  910. /*
  911.  * Returns TRUE when messages should be printed to stderr.
  912.  * This is used when there is no valid screen, so we can see error messages.
  913.  * If termcap is not active, we may be writing in an alternate console
  914.  * window, cursor positioning may not work correctly (window size may be
  915.  * different, e.g. for WIN32 console) or we just don't know where the
  916.  * cursor is.
  917.  */
  918.     static int
  919. msg_use_printf()
  920. {
  921.     return (!msg_check_screen()
  922. #ifdef WIN32
  923.         || !termcap_active
  924. #endif
  925.         || (swapping_screen() && !termcap_active)
  926.            );
  927. }
  928.  
  929.     static void
  930. msg_screen_putchar(c, attr)
  931.     int        c;
  932.     int        attr;
  933. {
  934.     msg_didout = TRUE;        /* remember that line is not empty */
  935.     screen_putchar(c, msg_row, msg_col, attr);
  936.     if (++msg_col >= Columns)
  937.     {
  938.     msg_col = 0;
  939.     ++msg_row;
  940.     }
  941. }
  942.  
  943.     void
  944. msg_moremsg(full)
  945.     int        full;
  946. {
  947.     int        attr;
  948.  
  949.     attr = highlight_attr[HLF_M];
  950.     screen_puts((char_u *)"-- More --", (int)Rows - 1, 0, attr);
  951.     if (full)
  952.     screen_puts((char_u *)
  953.         " (RET: line, SPACE: page, d: half page, q: quit)",
  954.         (int)Rows - 1, 10, attr);
  955. }
  956.  
  957. /*
  958.  * msg_check_screen - check if the screen is initialized.
  959.  * Also check msg_row and msg_col, if they are too big it may cause a crash.
  960.  * While starting the GUI the terminal codes will be set for the GUI, but the
  961.  * output goes to the terminal.  Don't use the terminal codes then.
  962.  */
  963.     static int
  964. msg_check_screen()
  965. {
  966.     if (!full_screen || !screen_valid(FALSE))
  967.     return FALSE;
  968.  
  969.     if (msg_row >= Rows)
  970.     msg_row = Rows - 1;
  971.     if (msg_col >= Columns)
  972.     msg_col = Columns - 1;
  973.     return TRUE;
  974. }
  975.  
  976. /*
  977.  * clear from current message position to end of screen
  978.  * Note: msg_col is not updated, so we remember the end of the message
  979.  * for msg_check().
  980.  */
  981.     void
  982. msg_clr_eos()
  983. {
  984.     if (!msg_check_screen()
  985. #ifdef WIN32
  986.         || !termcap_active
  987. #endif
  988.         || (swapping_screen() && !termcap_active)
  989.                         )
  990.     {
  991.     if (full_screen)    /* only when termcap codes are valid */
  992.     {
  993.         if (*T_CD)
  994.         out_str(T_CD);    /* clear to end of display */
  995.         else if (*T_CE)
  996.         out_str(T_CE);    /* clear to end of line */
  997.     }
  998.     }
  999.     else
  1000.     {
  1001.     screen_fill(msg_row, msg_row + 1, msg_col, (int)Columns, ' ', ' ', 0);
  1002.     screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
  1003.     }
  1004. }
  1005.  
  1006. /*
  1007.  * end putting a message on the screen
  1008.  * call wait_return if the message does not fit in the available space
  1009.  * return TRUE if wait_return not called.
  1010.  */
  1011.     int
  1012. msg_end()
  1013. {
  1014.     /*
  1015.      * if the string is larger than the window,
  1016.      * or the ruler option is set and we run into it,
  1017.      * we have to redraw the window.
  1018.      * Do not do this if we are abandoning the file or editing the command line.
  1019.      */
  1020.     if (!exiting && msg_check() && State != CMDLINE)
  1021.     {
  1022.     wait_return(FALSE);
  1023.     return FALSE;
  1024.     }
  1025.     out_flush();
  1026.     return TRUE;
  1027. }
  1028.  
  1029. /*
  1030.  * If the written message has caused the screen to scroll up, or if we
  1031.  * run into the shown command or ruler, we have to redraw the window later.
  1032.  */
  1033.     int
  1034. msg_check()
  1035. {
  1036.     if (msg_scrolled || (msg_row == Rows - 1 && msg_col >= sc_col))
  1037.     {
  1038.     redraw_all_later(NOT_VALID);
  1039.     redraw_cmdline = TRUE;
  1040.     return TRUE;
  1041.     }
  1042.     return FALSE;
  1043. }
  1044.  
  1045. /*
  1046.  * May write a string to the redirection file.
  1047.  */
  1048.     static void
  1049. redir_write(s)
  1050.     char_u    *s;
  1051. {
  1052.     static int        cur_col = 0;
  1053.  
  1054.     if (redir_fd != NULL && !redir_off)
  1055.     {
  1056.     /* If the string doesn't start with CR or NL, go to msg_col */
  1057.     if (*s != '\n' && *s != '\r')
  1058.     {
  1059.         while (cur_col < msg_col)
  1060.         {
  1061.         fputs(" ", redir_fd);
  1062.         ++cur_col;
  1063.         }
  1064.     }
  1065.  
  1066.     fputs((char *)s, redir_fd);
  1067.  
  1068.     /* Adjust the current column */
  1069.     while (*s)
  1070.     {
  1071.         if (*s == '\r' || *s == '\n')
  1072.         cur_col = 0;
  1073.         else if (*s == '\t')
  1074.         cur_col += (8 - cur_col % 8);
  1075.         else
  1076.         ++cur_col;
  1077.         ++s;
  1078.     }
  1079.     }
  1080. }
  1081.  
  1082. /*
  1083.  * Give a warning message (for searching).
  1084.  * Use 'w' highlighting and may repeat the message after redrawing
  1085.  */
  1086.     void
  1087. give_warning(message, hl)
  1088.     char_u  *message;
  1089.     int        hl;
  1090. {
  1091.     keep_msg = NULL;
  1092.     if (hl)
  1093.     keep_msg_attr = highlight_attr[HLF_W];
  1094.     else
  1095.     keep_msg_attr = 0;
  1096.     if (msg_attr(message, keep_msg_attr) && !msg_scrolled)
  1097.     keep_msg = message;
  1098.     msg_didout = FALSE;        /* overwrite this message */
  1099.     msg_nowait = TRUE;        /* don't wait for this message */
  1100.     msg_col = 0;
  1101. }
  1102.  
  1103. /*
  1104.  * Advance msg cursor to column "col".
  1105.  */
  1106.     void
  1107. msg_advance(col)
  1108.     int        col;
  1109. {
  1110.     if (col >= Columns)        /* not enough room */
  1111.     col = Columns - 1;
  1112.     while (msg_col < col)
  1113.     msg_putchar(' ');
  1114. }
  1115.